package com.cpit.platform.common.dao;

import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.util.Collection;
import java.util.Iterator;

/**
 * 条件接口 
 * 用户提供条件表达式接口 
 */  
public interface Criterion {
	//用来分隔两个独立条件
	public static final String SEPARATOR_SEMICOLON = ";";
	public enum Operator {
        EQ("="), NE("!="), LIKE("like"), GT(">"),
		LT("<"), GTE(">="), LTE("<="), AND("and"),
		OR("or"), BETWEEN("between"), ISNULL("is_null"), ISNOTNULL("is_not_null"),
		ISEMPTY("is_empty"), ISNOTEMPTY("is_not_empty"),IN("in"),NOTIN("not_in");

		private Operator(String name){
			this.name = name;
		}
        private String name;
    }
	
	public enum MatchMode {  
		START("start"), END("end"), ANYWHERE("anywhere");
		private MatchMode(String name){
			this.name = name;
		}
		private String name;
	}  
	
	public enum Projection {
		MAX("max"), MIN("min"), AVG("avg"), LENGTH("length"), SUM("sum"), COUNT("count");
		private Projection(String name){
			this.name = name;
		}
		private String name;
	}
	
    public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query,
                                 CriteriaBuilder builder);


	public static Predicate toSimplePredicate(Operator operator,CriteriaBuilder builder, Expression expression,
										Object value,MatchMode matchMode){
		return toSimplePredicate(operator,builder, expression,
				value,null,null, matchMode);
	}
	public static Predicate toSimplePredicate(Operator operator,CriteriaBuilder builder, Expression expression,
										Object value,Object minValue,Object maxValue, MatchMode matchMode){
		switch (operator) {
			case EQ:
				return builder.equal(expression, value);
			case NE:
				return builder.notEqual(expression, value);
			case LIKE:
				switch(matchMode){
					case START :
						return builder.like((Expression<String>) expression, value + "%");
					case END :
						return builder.like((Expression<String>) expression, "%" + value);
					case ANYWHERE :
						return builder.like((Expression<String>) expression, "%" + value + "%");
					default :
						return builder.like((Expression<String>) expression, "%" + value + "%");
				}
			case LT:
				return builder.lessThan(expression, (Comparable) value);
			case GT:
				return builder.greaterThan(expression, (Comparable) value);
			case LTE:
				return builder.lessThanOrEqualTo(expression, (Comparable) value);
			case GTE:
				return builder.greaterThanOrEqualTo(expression, (Comparable) value);
			case ISNOTNULL:
				return builder.isNotNull(expression);
			case ISNULL:
				return builder.isNull(expression);
			case ISEMPTY:
				return builder.isEmpty(expression);
			case ISNOTEMPTY:
				return builder.isNotEmpty(expression);
			case BETWEEN:
				return builder.between(expression, (Comparable)minValue , (Comparable) maxValue);
			case IN:
			case NOTIN:
				if ((value == null) || !(value instanceof Collection)) {
					return null;
				}
				Iterator iterator = ((Collection)value).iterator();
				CriteriaBuilder.In in = builder.in(expression);
				while (iterator.hasNext()) {
					in.value(iterator.next());
				}
				return (operator == Operator.IN) ? in:builder.not(in);
			default:
				return null;
		}
	}

	public static Path getPath(Root<?> root,String fieldName){
		Path expression = null;
		if(fieldName.contains(".")){
			String[] names = StringUtils.split(fieldName, ".");
			expression = root.get(names[0]);
			for (int i = 1; i < names.length; i++) {
				expression = expression.get(names[i]);
			}
		}else{
			expression = root.get(fieldName);
		}
		return expression;
	}
}
